package com.heima.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.exception.CustException;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.LoginDTO;
import com.heima.model.user.pojos.ApUser;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserLoginService;
import com.heima.utils.common.AppJwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.validation.Valid;
import java.sql.Wrapper;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author mrchen
 * @date 2022/5/2 9:28
 */
@Service
@Slf4j
public class ApUserLoginServiceImpl implements ApUserLoginService {

    @Autowired
    ApUserMapper apUserMapper;

    @Override
    public ResponseResult login(LoginDTO dto) {
        // 1. 判断手机号 密码 是否为空
        String phone = dto.getPhone();
        String password = dto.getPassword();
        if (StringUtils.isNotBlank(phone) && StringUtils.isNotBlank(password)) {
            //    1.1 如果不为空 查询手机号对应的用户是否存在
            ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, phone));
            if (Objects.isNull(apUser)) {
                CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "对应的用户信息不存在");
            }
            //    1.2 对比输入的密码和 数据库中密码是否一致
            String dbPassword = apUser.getPassword();
            String inputPassword = DigestUtils.md5DigestAsHex((password + apUser.getSalt()).getBytes());
            if (!inputPassword.equals(dbPassword)) {
                CustException.cust(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR, "密码错误");
            }
            //    1.3 颁发token 并返回  （user    token  ）
            String token = AppJwtUtil.getToken(Long.valueOf(apUser.getId()));
            Map result = new HashMap<>();
            result.put("token", token);
            apUser.setSalt("");
            apUser.setPassword("");
            result.put("user", apUser);
            return ResponseResult.okResult(result);
        } else {
            // 2. 如果手机号或密码为空 采用设备id登陆
            if (dto.getEquipmentId() == null) {
                //    2.1  判断设备id是否存在
                return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
            }
            //    2.2  直接颁发token  userId存储 0
            String token = AppJwtUtil.getToken(0L);
            Map result = new HashMap<>();
            result.put("token", token);
            return ResponseResult.okResult(result);
        }
    }

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    public ResponseResult loginCode(LoginDTO dto) {
////        //判断手机号是否存在 @Notnull
//        //设置失效时间
//        String count = dto.getPhone() + "_count";
//        Boolean key = redisTemplate.hasKey(count);
//        //一小时内输入错误次数
//        Long failedCount = redisTemplate.opsForValue().increment(count);
//        String phone = dto.getPhone();
//        String code = dto.getPhone() + "_code";
//        //判断key是否存在 设置失效时间
//        if (!key) {
//            redisTemplate.opsForValue().set("count", "1", 1, TimeUnit.HOURS);
//        }
//        String redisCode = (String) redisTemplate.opsForValue().get(code);
//        if (StringUtils.isBlank(redisCode)) {
//            log.error("验证码不存在,或者已失效");
//            CustException.cust(AppHttpCodeEnum.SIG_TIMEOUT, "验证码不存在,或者已失效");
//        }
//        if (failedCount < 3) {
//            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "验证码错误请稍后重试");
//        } else {
//            redisTemplate.opsForValue().set("dayCount",1,1,TimeUnit.DAYS);
//            //设置redis缓存黑名单 并设置失效时间
//            redisTemplate.opsForValue().set("balcklist", phone, 60, TimeUnit.SECONDS);
//            //count 归零
//            redisTemplate.opsForValue().decrement(count, 3);
//            //提示错误次数过多 稍后重试
//            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "错误次数过多请一分钟后重试");
//        if (redisTemplate.opsForValue().get()>= 2) {
//
//            //暂时冻结账号一天
//            redisTemplate.opsForValue().set("blacklist", phone, 1, TimeUnit.DAYS);
//
//            CustException.cust(AppHttpCodeEnum.NO_OPERATOR_AUTH, "您的账号已锁定请联系管理员重新激活");
//        }
//        }
//        //验证码对比
//        if (!redisCode.equals(dto.getCode() + "")) {
//            //验证码输入错误   删除redis中的验证码 code  保证唯一
//            log.error("验证码输入错误");
//        }

        ////判断手机号对应的账户是否存在 存在判断验证码=redis
        String phone = dto.getPhone();
        Short code = dto.getCode();
        ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, phone));
        //判断账户是否存在
        if (apUser==null) CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"账户不存在,请先注册");
        //判断账户状态
        if (apUser.getStatus())CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"账号异常,请联系管理员");
        Boolean flag = redisTemplate.hasKey(apUser.getPhone());
        String userLock = "user_lock";
        String loginCount = "login_count";
        if (flag){
            //验证码正确
            if (code.equals(redisTemplate.opsForValue().get(phone))) {
                //账户是否锁定
                if (!redisTemplate.hasKey(userLock + dto.getPhone())) {
                    return ResponseResult.okResult();
                }
            }else {
                // 同手机号   1个小时内   连续3次   手机验证码输入错误，
                //记录失败次数
                Boolean first = redisTemplate.opsForValue().setIfAbsent(dto.getPhone() + loginCount, "1", 60, TimeUnit.MINUTES);
                assert  first != null;
                if (!first){
                    //解除禁用后， 如果同一天，同一手机号再次 一小时内 连续3次输错 修改用户状态 设置暂时冻结状态，需要联系管理员激活
                    String lockKey = (String) redisTemplate.opsForValue().get(dto.getPhone() + loginCount);
                    if (redisTemplate.hasKey(dto.getPhone() + loginCount) && Integer.parseInt(lockKey) > 3) {
                        redisTemplate.opsForValue().increment(dto.getPhone() + loginCount);
                        String lockCount = (String) redisTemplate.opsForValue().get(dto.getPhone() + loginCount);
                        if (Integer.parseInt(lockCount) >= 6){
                            apUser.setStatus(true);
                            apUserMapper.updateById(apUser);
                            CustException.cust(AppHttpCodeEnum.LOGIN_STATUS_ERROR);
                        }
                        CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"验证码错误，还有" + (6 - Integer.parseInt(lockCount)) + "次封号");
                    }

                    //第二次递增
                    redisTemplate.opsForValue().increment(dto.getPhone() + loginCount);
                    String count = (String) redisTemplate.opsForValue().get(dto.getPhone() + loginCount);
                    assert count != null;
                    if (Integer.parseInt(count) >= 3) {
                        //锁定账号
                        //再次登录  提示错误次数过多 请5分钟后重试(演示1分即可) ， redis中缓存禁用黑名单  并设置失效时间
                        redisTemplate.opsForValue().set(userLock + dto.getPhone(),"1",60,TimeUnit.SECONDS);
                        CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"失败次数超过3次,账号已锁定,请在5分钟后重试");
                    }
                }
                CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"验证码输入错误");
            }
        }


        return ResponseResult.okResult();
    }


}

